<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/4/9
 * Time: 13:11
 */

namespace common\business\db;


use common\business\CommonHelper;
use common\business\ifs\DbCrud;
use common\business\ifs\LogInterface;
use common\consts\CommonResources;
use common\consts\Consts;
use common\helpers\StringUtil;
use common\models\Log;
use common\result\ActionResult;
use yii\db\ActiveRecord;
use Yii;
use yii\db\Exception;
use yii\helpers\Json;

abstract class DbCrudWithLog extends DbCrud implements LogInterface
{
    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function saveRecordWithLogUnsafe($record, $log){
        $actionIsSuccess = true;
        if (!$record->save()) {
            $dbErrorMsg = Json::encode($record->getErrors());
            $this->addError('SaveRecordWithLog', $dbErrorMsg);
            $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
            $actionIsSuccess = false;
        }
        $this->persistLog($log);
        return $actionIsSuccess;
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function saveRecordWithLogSafe($record, $log)
    {
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$record->save()) {
                $dbErrorMsg = Json::encode($record->getErrors());
                $this->addError('SaveRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
                $transaction->rollBack();
                return false;
            }

            if (!$this->persistLog($log)) {
                $transaction->rollBack();
                return false;
            }

            $transaction->commit();
            return true;
        } catch (Exception $ex) {
            $this->addError('SaveRecordWithLog', $ex->getMessage());
            return false;
        }
    }

    /**
     * @param $record ActiveRecord
     * @return bool
     */
    public function saveRecordSafe($record){
        $log = new Log();
        $log->action = CommonResources::ACTION_NAME_MSG('Save', 'Record', CommonHelper::getPrintName($record));
        $log->memo = StringUtil::getShortString(Json::encode($record->attributes), Consts::MAX_STRING_LENGTH);
        return $this->saveRecordWithLogSafe($record, $log);
    }

    /**
     * @param $record ActiveRecord
     * @return bool
     */
    public function saveRecordUnsafe($record){
        $log = new Log([
            'action' => CommonResources::ACTION_MSG('Save', 'Record'),
            'memo' => Json::encode($record->attributes),
        ]);
        return $this->saveRecordWithLogUnsafe($record, $log);
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function deleteRecordWithLogUnsafe($record, $log){
        try {
            $actionIsSuccess = true;
            if (!$record->delete()) {
                $dbErrorMsg = Json::encode($record->getErrors());
                $this->addError('DeleteRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg);
                $actionIsSuccess = false;
            }
            $this->persistLog($log);
            return $actionIsSuccess;
        } catch (\Exception $e) {
            $dbErrorMsg = CommonHelper::getExceptionMsg($e);
            $this->addError('DeleteRecordWithLog', $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg));
            return false;
        }
    }

    /**
     * @param $obj ActiveRecord
     * @return ActionResult
     */
    public function create($obj){
        $action = Yii::t('app', 'Create');
        $modelClass = Yii::t('app', get_class($obj));

        $cResult = parent::create($obj);

        $log = new Log();
        $log->action = CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($obj));
        $log->new_content = StringUtil::getShortString(Json::encode($obj->attributes), Consts::MAX_STRING_LENGTH);

        $this->appendLogMemoByResultAndPersist($log, $cResult);

        if (!$cResult->isSuccess) {
            $dbErrorMsg = $cResult->getMessage();
            $this->addError($action, $dbErrorMsg);
            $log->memo = StringUtil::getShortString($log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg), Consts::MAX_STRING_LENGTH);
        }
        $this->persistLog($log);

        return $cResult;
    }


    /**
     * @param $log Log
     * @param $result ActionResult
     */
    protected function appendLogMemoByResultAndPersist($log, $result){
        if (!$result->isSuccess) {
            $memoStr = sprintf('%s|%s', $log->memo, $result->getMessage());
            $log->memo = StringUtil::getShortString($memoStr, Consts::MAX_STRING_LENGTH);
        }
        $this->persistLog($log);
    }

    /**
     * @param $obj ActiveRecord
     * @return ActionResult
     */
    public function delete($obj){
        $action = Yii::t('app', 'Delete');
        $modelClass = Yii::t('app', get_class($obj));
        try {
            $dResult = parent::delete($obj);
            $log = new Log();
            $log->action = CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($obj));
            $log->memo = StringUtil::getShortString(Json::encode($obj->attributes), Consts::MAX_STRING_LENGTH);

            $this->appendLogMemoByResultAndPersist($log, $dResult);

            return $dResult;
        } catch (\Exception $e) {
            $dbErrorMsg = CommonHelper::getExceptionMsg($e);
            $this->addError($action, $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG($action, $modelClass, $dbErrorMsg));
            return new ActionResult(false, CommonResources::ACTION_FAIL_MSG($action, $modelClass, $dbErrorMsg));
        }
    }

    /**
     * @param $obj ActiveRecord
     * @return ActionResult
     */
    public function update($obj)
    {
        $action = Yii::t('app', 'Update');
        $modelClass = Yii::t('app', get_class($obj));

        $uResult = parent::update($obj);
        $log = new Log();
        $log->action = CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($obj));
        $log->new_content = StringUtil::getShortString(Json::encode($obj->attributes), Consts::MAX_STRING_LENGTH);

        $this->appendLogMemoByResultAndPersist($log, $uResult);

        return $uResult;
    }

    /**
     * @param $log Log
     * @return bool
     */
    public function persistLog($log)
    {
        $actionIsSuccess = $log->save();
        if (!$actionIsSuccess) {
            $dbErrorMsg = Json::encode($log->getErrors());
            $this->addError('persistLog', $dbErrorMsg);
            $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Persist', 'Log', $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->memo));
        }
        return $actionIsSuccess;
    }
}